import pickle
import hashlib
from typing import Sequence, Dict, Any
from schedule.PowerSchedule import PowerSchedule
from utils.Seed import Seed

def get_path_id(coverage: Any) -> str:
    """Returns a unique hash for the covered statements"""
    pickled = pickle.dumps(sorted(coverage))
    return hashlib.md5(pickled).hexdigest()


class PathPowerSchedule(PowerSchedule):

    def __init__(self, exponent: float = 1.0) -> None:
        super().__init__()
        # TODO
        self.path_frequencies: Dict[str, int] = {}
        self.exponent = exponent

    def update_path_frequencies(self, population):
        """get the frequencies of each path based on coverage hash"""
        for item in population:
            if isinstance(item, str):
                continue
            path_id = get_path_id(item.coverage)
            if path_id in self.path_frequencies:
                self.path_frequencies[path_id] += 1
            else:
                self.path_frequencies[path_id] = 1

    def assign_energy(self, population: Sequence[Seed]) -> None:
        """Assign exponential energy inversely proportional to path frequency"""
        # TODO
        self.update_path_frequencies(population)

        for seed in population:
            path_id = get_path_id(seed.coverage)
            freq = self.path_frequencies.get(path_id, 1)
            seed.energy = 1.0 / (freq ** self.exponent)
